<template>
    <el-button @click="handleSave">提交</el-button>
    <!-- 新增: 内联工具栏 -->
    <div class="container">
        <div class="map-toolbar">
            <button
                class="tool-btn"
                :class="{ active: currentActiveOverlay === 'polygon' }"
                @click="activate('polygon')"
            >
                多边形
            </button>
            <button
                class="tool-btn"
                :class="{ active: currentActiveOverlay === 'circle' }"
                @click="activate('circle')"
            >
                圆形
            </button>
            <button
                class="tool-btn"
                :class="{ active: currentActiveOverlay === 'rectangle' }"
                @click="activate('rectangle')"
            >
                矩形
            </button>
            <button class="tool-btn danger" @click="clearAll">清除所有</button>
        </div>
        <div id="mapContainer" class="map-container"></div>
        <div class="search-panel">
            <h2 class="search-title"><i class="fas fa-search"></i> 地点搜索</h2>

            <div class="search-box">
                <input
                    v-model="searchQuery"
                    @keyup.enter="searchPOI"
                    placeholder="输入地点关键字..."
                    class="search-input"
                />
                <button
                    @click="searchPOI"
                    :disabled="searching || !searchQuery"
                    class="search-btn"
                >
                    <i class="fas fa-search"></i> 搜索
                </button>
            </div>

            <div class="results-container">
                <div v-if="searching" class="loading">
                    <i class="fas fa-spinner fa-spin"></i> 搜索中...
                </div>
                <div
                    v-else-if="searchResults.length === 0 && searchQuery"
                    class="no-results"
                >
                    <i class="fas fa-search-location"></i>
                    <p>没有找到相关地点</p>
                </div>

                <div v-else-if="!searchQuery" class="no-results">
                    <i class="fas fa-info-circle"></i>
                    <p>请输入关键字进行搜索</p>
                </div>

                <div v-else>
                    <div
                        v-for="(result, index) in searchResults"
                        :key="index"
                        class="result-item"
                        @click="centerMap(result)"
                    >
                        <h3>{{ result.title }}</h3>
                        <p>
                            <i class="fas fa-map-marker-alt"></i>
                            {{ result.address }}
                        </p>
                        <p>
                            <i class="fas fa-crosshairs"></i>
                            {{ result.lat.toFixed(6) }},
                            {{ result.lng.toFixed(6) }}
                        </p>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import {
    ref,
    shallowRef,
    markRaw,
    onMounted,
    onUnmounted,
    nextTick,
    watch,
} from 'vue'

let geoList = [
    {
        id: '1962452281934721024',
        templateMainId: '1962437231316545536',
        templateName: '冻豆腐',
        provinceCode: '310000',
        provinceName: '上海市',
        cityCode: '',
        cityName: '',
        regionCode: '',
        regionName: '',
        geofenceType: 'CIRCLE',
        sid: 0,
        gfid: 0,
        center: '121.239561,31.317573',
        radius: 10497,
        points: '',
        area: 345.5798,
        remark: '',
        tenantId: '2024090314001',
        delFlag: 0,
        createBy: 'e9ca23d68d884d4ebb19d07889727dae',
        createTime: '2025-09-01 17:47:38',
        updateBy: '',
        updateTime: '2025-09-01 17:47:38',
    },
    {
        id: '1962452282190573568',
        templateMainId: '1962437231316545536',
        templateName: '冻豆腐',
        provinceCode: '310000',
        provinceName: '上海市',
        cityCode: '',
        cityName: '',
        regionCode: '',
        regionName: '',
        geofenceType: 'POLYGON',
        sid: 0,
        gfid: 0,
        center: '',
        radius: 0,
        points: '121.296201,31.069936;121.302494,31.013859;121.478707,31.010622;121.464861,31.087184;121.357875,31.102273;',
        area: 145.4538,
        remark: '',
        tenantId: '2024090314001',
        delFlag: 0,
        createBy: 'e9ca23d68d884d4ebb19d07889727dae',
        createTime: '2025-09-01 17:47:38',
        updateBy: '',
        updateTime: '2025-09-01 17:47:38',
    },
    {
        id: '1962437231698227200',
        templateMainId: '1962437231316545536',
        templateName: '冻豆腐',
        provinceCode: '310000',
        provinceName: '上海市',
        cityCode: '',
        cityName: '',
        regionCode: '',
        regionName: '',
        geofenceType: 'RECTANGLE',
        sid: 0,
        gfid: 0,
        center: '',
        radius: 0,
        points: '121.383697,31.120666;121.586944,31.120666;121.586944,31.300369;121.383697,31.300369;',
        area: 387.1009,
        remark: '',
        tenantId: '2024090314001',
        delFlag: 0,
        createBy: 'e9ca23d68d884d4ebb19d07889727dae',
        createTime: '2025-09-01 16:47:50',
        updateBy: 'e9ca23d68d884d4ebb19d07889727dae',
        updateTime: '2025-09-01 17:47:38',
    },
]
const searchQuery = ref('')
const searching = ref(false)
const searchResults = ref([])
let map = null
let markers = []
// 全局声明
declare global {
    interface Window {
        TMap: any
    }
}

// ---------------- 常量 & 类型 ----------------
const TENCENT_MAP_KEY = '   '
const MAP_CENTER_LAT = 39.908802
const MAP_CENTER_LNG = 116.397502

type OverlayId = 'polygon' | 'circle' | 'rectangle'
interface DrawnShape {
    id: string
    type: OverlayId
    paths: any[]
}
interface OverlayGroup {
    polygon: any
    circle: any
    rectangle: any
}

// 新增: 矩形回显改为多边形的开关
const RECTANGLE_ECHO_AS_POLYGON = true

// ---------------- 状态引用 ----------------
const mapInstance = shallowRef<any>(null)
const geometryEditorRef = shallowRef<any>(null)
const overlaysRef = shallowRef<OverlayGroup | null>(null)
const drawnShapes = ref<DrawnShape[]>([])
const sdkLoadedPromise = loadTencentMapSDKOnce()
const currentActiveOverlay = ref<OverlayId | null>(null)

// 新增: 当前选中图形
const selectedGeometry = ref<{ id: string; overlayId: OverlayId } | null>(null)

// ---------------- SDK 加载（单例） ----------------
function loadTencentMapSDKOnce(): Promise<any> {
    if (window.TMap && window.TMap.tools) return Promise.resolve(window.TMap)
    const exist = document.querySelector<HTMLScriptElement>(
        'script[data-tmap-sdk="1"]'
    )
    if (exist) {
        return new Promise((resolve, reject) => {
            const check = () =>
                window.TMap && window.TMap.tools
                    ? resolve(window.TMap)
                    : reject(new Error('Tencent Map tools 加载失败'))
            exist.addEventListener('load', check, { once: true })
            exist.addEventListener(
                'error',
                () => reject(new Error('Tencent Map SDK 脚本加载失败')),
                { once: true }
            )
        })
    }
    return new Promise((resolve, reject) => {
        const script = document.createElement('script')
        script.dataset.tmapSdk = '1'
        script.type = 'text/javascript'
        script.charset = 'utf-8'
        script.src = `https://map.qq.com/api/gljs?libraries=tools&v=1.exp&worker=false&key=${TENCENT_MAP_KEY}`
        script.onload = () => {
            if (window.TMap && window.TMap.tools) {
                resolve(window.TMap)
            } else {
                reject(new Error('Tencent Map tools 库未就绪'))
            }
        }
        script.onerror = () => reject(new Error('Tencent Map SDK 加载失败'))
        document.head.appendChild(script)
    })
}

// ---------------- 初始化总控 ----------------
async function ensureMapAndEditor() {
    if (geometryEditorRef.value) return
    await sdkLoadedPromise
    initMap()
    initEditorWorkflow()
}

// ---------------- 地图 ----------------
function initMap() {
    if (mapInstance.value) return
    const mapDom = document.getElementById('mapContainer')
    if (!mapDom) throw new Error('地图容器不存在')
    mapInstance.value = markRaw(
        new window.TMap.Map(mapDom, {
            center: new window.TMap.LatLng(MAP_CENTER_LAT, MAP_CENTER_LNG),
            zoom: 10,
            worker: false,
        })
    )
}

// ---------------- 覆盖物 & 编辑器工作流 ----------------
function initEditorWorkflow() {
    if (!mapInstance.value) return
    createOverlays()
    createGeometryEditor()
    bindEditorEvents()
}
// 创建覆盖物组
function createOverlays() {
    if (!window.TMap) return
    const polygon = markRaw(
        new window.TMap.MultiPolygon({
            // 可选：增加一个默认样式，避免有些版本默认透明
            styles: {
                poly: new window.TMap.PolygonStyle({
                    color: 'rgba(24,144,255,0.25)',
                    showBorder: true,
                    borderColor: '#1890ff',
                    borderWidth: 2,
                }),
            },
        })
    )
    const circle = markRaw(
        new window.TMap.MultiCircle({
            styles: {
                circle: new window.TMap.CircleStyle({
                    color: 'rgba(0,180,42,0.25)',
                    showBorder: true,
                    borderColor: '#00b42a',
                    borderWidth: 2,
                }),
            },
        })
    )
    // 修改: rectangle 增加样式（否则可能不渲染）
    const rectangle = markRaw(
        new window.TMap.MultiRectangle({
            styles: {
                rect: new window.TMap.RectangleStyle({
                    color: 'rgba(255,165,0,0.25)',
                    showBorder: true,
                    borderColor: '#ff9900',
                    borderWidth: 2,
                }),
            },
        })
    )
    polygon.setMap(mapInstance.value)
    circle.setMap(mapInstance.value)
    rectangle.setMap(mapInstance.value)
    overlaysRef.value = { polygon, circle, rectangle }
}
// 创建几何编辑器
function createGeometryEditor() {
    if (!overlaysRef.value) return
    geometryEditorRef.value = markRaw(
        new window.TMap.tools.GeometryEditor({
            map: mapInstance.value,
            overlayList: [
                { overlay: overlaysRef.value.polygon, id: 'polygon' },
                { overlay: overlaysRef.value.circle, id: 'circle' },
                { overlay: overlaysRef.value.rectangle, id: 'rectangle' },
            ],
            // 修改: 初始不进入绘制模式，防止一进页面就能画
            actionMode: window.TMap.tools.constants.EDITOR_ACTION.INTERACT,
            snappable: true,
            selectable: true,
        })
    )
    // 初始强制空闲
    ensureIdleMode()
    try {
        geometryEditorRef.value.setKeyboardDeleteEnable?.(true)
        geometryEditorRef.value.setKeyboardEscEnable?.(true)
        geometryEditorRef.value.setKeyboardCtrlEnable?.(true)
    } catch {}
}

// 新增: 统一空闲模式（禁止绘制）
function ensureIdleMode() {
    if (!geometryEditorRef.value) return
    const CONST = window.TMap.tools.constants.EDITOR_ACTION
    geometryEditorRef.value.setActionMode(CONST.INTERACT)
    geometryEditorRef.value.stop()
    currentActiveOverlay.value = null
}

// 绑定编辑器事件
function bindEditorEvents() {
    if (!geometryEditorRef.value) return
    geometryEditorRef.value.on('draw_complete', (geometry: any) => {
        const active = geometryEditorRef.value?.getActiveOverlay()
            ?.id as OverlayId
        if (!active) return
        const norm = normalizePaths(active, geometry)
        upsertShape(geometry.id, active, norm)
        syncAll('create_done') // 改: 统一调用
        selectedGeometry.value = { id: geometry.id, overlayId: active }
        enterEditMode()
        resetDrawState()
        if (active === 'rectangle')
            console.log('[Rectangle Created]', geometry.id, norm)
    })

    // 新增: 图形选中
    geometryEditorRef.value.on('geometry_select', (e: any) => {
        if (!e?.geometry?.id || !e?.overlayId) return
        selectedGeometry.value = {
            id: e.geometry.id,
            overlayId: e.overlayId as OverlayId,
        }
        enterEditMode()
    })

    // 新增: 图形取消选中
    geometryEditorRef.value.on('geometry_unselect', () => {
        if (selectedGeometry.value)
            updateShapeFromOverlay(
                selectedGeometry.value.id,
                selectedGeometry.value.overlayId
            )
        syncAll('edit_done')
        selectedGeometry.value = null
        geometryEditorRef.value!.setActionMode(
            window.TMap.tools.constants.EDITOR_ACTION.INTERACT
        )
    })

    // 新增: 图形坐标或形状修改同步
    geometryEditorRef.value.on?.('geometry_change', (e: any) => {
        if (e?.geometry?.id && e?.overlayId) {
            const t = e.overlayId as OverlayId
            const norm = normalizePaths(t, e.geometry)
            updateShapePaths(e.geometry.id, norm)
            syncAll('change')
        }
    })

    // 新增: 可能的调节完成事件 (不同版本命名可能不同)
    geometryEditorRef.value.on?.('adjust_complete', (e: any) => {
        if (e?.geometry?.id && e?.overlayId) {
            const t = e.overlayId as OverlayId
            const norm = normalizePaths(t, e.geometry)
            updateShapeFromOverlay(e.geometry.id, t)
            updateShapePaths(e.geometry.id, norm)
            syncAll('adjust_complete')
        }
    })
    geometryEditorRef.value.on?.('geometry_adjust', (e: any) => {
        if (e?.geometry?.id && e?.overlayId) {
            const t = e.overlayId as OverlayId
            const norm = normalizePaths(t, e.geometry)
            updateShapePaths(e.geometry.id, norm)
            // 可选择是否重建; 若需要最新立刻体现则:
            syncAll('adjust')
        }
    })

    // 新增: 图形被删除事件 (若 SDK 支持)
    geometryEditorRef.value.on?.('geometry_delete', (e: any) => {
        const delId = e?.geometry?.id
        if (!delId) return
        if (!drawnShapes.value.some((g) => g.id === delId)) return
        drawnShapes.value = drawnShapes.value.filter((g) => g.id !== delId)
        syncAll('delete_done_event')
        if (selectedGeometry.value?.id === delId) selectedGeometry.value = null
    })
}

// 新增: 进入编辑模式 (允许移动/顶点编辑)
function enterEditMode() {
    if (!geometryEditorRef.value) return
    const CONST = window.TMap.tools.constants.EDITOR_ACTION
    const editAction = CONST.EDIT || CONST.INTERACT
    geometryEditorRef.value.setActionMode(editAction)
}

// 新增: 退出编辑 (Esc)
function cancelEdit() {
    if (!geometryEditorRef.value) return
    // ESC 退出前同步一次
    if (selectedGeometry.value)
        updateShapeFromOverlay(
            selectedGeometry.value.id,
            selectedGeometry.value.overlayId
        )
    syncAll('edit_done')
    selectedGeometry.value = null
    geometryEditorRef.value.setActionMode(
        window.TMap.tools.constants.EDITOR_ACTION.INTERACT
    )
    geometryEditorRef.value.clearSelected?.()
}

// 新增: 仅针对当前 overlay 删除一个几何的安全函数
function safeDeleteGeometry(overlay: any, id: string) {
    if (!overlay) return false
    try {
        if (typeof overlay.remove === 'function') {
            overlay.remove(id)
            return true
        }
        if (typeof overlay.deleteGeometry === 'function') {
            overlay.deleteGeometry(id)
            return true
        }
    } catch (e) {
        console.warn('[safeDeleteGeometry] API 删除失败, fallback 过滤方式', e)
    }
    try {
        const geos = overlay.getGeometries?.() || []
        const filtered = geos.filter((g: any) => g.id !== id)
        // 最小结构回写, 避免把 SDK 内部运行态字段写回导致其它 overlay 受影响
        const minimal = filtered.map((g: any) => ({
            id: g.id,
            paths: g.paths, // 对 circle / rectangle SDK 可能使用 center/radius/bounds，原 geos 仍会包含；若 paths 不存在继续保留其它字段
            center: g.center,
            radius: g.radius,
            bounds: g.bounds,
        }))
        if (typeof overlay.setGeometries === 'function') {
            overlay.setGeometries(minimal)
            return true
        }
    } catch (e) {
        console.warn('[safeDeleteGeometry] 过滤回写失败', e)
    }
    return false
}

// 修改: resetDrawState 退出绘制后允许交互选择
function resetDrawState() {
    ensureIdleMode()
}

// 新增: 覆盖物激活函数（原先被注释掉）
function setActiveOverlay(id: OverlayId) {
    if (!geometryEditorRef.value) {
        console.warn('[SetActiveOverlay] GeometryEditor 未就绪')
        return
    }
    currentActiveOverlay.value = id
    geometryEditorRef.value.setActiveOverlay(id)
    geometryEditorRef.value.setActionMode(
        window.TMap.tools.constants.EDITOR_ACTION.DRAW
    )
}

// 新增: 清空覆盖物函数（原先被注释掉）
function clearAllShapes() {
    if (!overlaysRef.value) return
    Object.values(overlaysRef.value).forEach((ov) => ov.setGeometries([]))
    drawnShapes.value = []
    rebuildShapesFromOverlays() // 新增
}

// 新增: 激活与清除按钮事件方法 (供模板调用)
function activate(id: OverlayId) {
    // 修复: 增加括号
    if (id === currentActiveOverlay.value) return
    setActiveOverlay(id)
}
function clearAll() {
    clearAllShapes()
    geometryEditorRef.value?.stop()
    currentActiveOverlay.value = null
}

// 新增: 通用路径归一化（当前仅处理 circle，若需可扩展 rectangle）
function normalizePaths(type: OverlayId, geometry: any) {
    if (type === 'circle') {
        return [
            {
                center: {
                    lat: geometry.center?.lat,
                    lng: geometry.center?.lng,
                },
                radius: geometry.radius,
            },
        ]
    }
    if (type === 'rectangle') {
        console.log('[Normalize Rectangle]', geometry)

        // 优先使用已有 paths（某些版本可能提供）
        if (
            geometry.paths &&
            geometry.paths.length &&
            geometry.paths[0]?.length
        ) {
            return [JSON.parse(JSON.stringify(geometry.paths[0]))]
        }
        const corners = extractRectangleCornersFromGeo(geometry)
        // 若第一次 corners 为空，延迟一次重取补偿
        if (!corners.length) {
            setTimeout(() => {
                try {
                    const geos =
                        overlaysRef.value?.rectangle?.getGeometries?.() || []
                    const g2 = geos.find((g: any) => g.id === geometry.id)
                    if (!g2) return
                    let retry = []
                    if (g2.paths && g2.paths.length && g2.paths[0]?.length) {
                        retry = JSON.parse(JSON.stringify(g2.paths[0]))
                    } else {
                        retry = extractRectangleCornersFromGeo(g2)
                    }
                    if (retry.length) {
                        updateShapePaths(geometry.id, [retry])
                        console.log(
                            '[Rectangle Retry Sync]',
                            geometry.id,
                            retry
                        )
                    }
                } catch (e) {
                    console.warn('[Rectangle Retry Error]', e)
                }
            }, 0)
        }
        return [corners]
    }
    // polygon
    return geometry.paths || []
}

// 修改: upsertShape / updateShapePaths 防止 paths 为 undefined
function upsertShape(id: string, type: OverlayId, paths: any[]) {
    const src = paths === undefined ? [] : paths
    const cloned = JSON.parse(JSON.stringify(src))
    const i = drawnShapes.value.findIndex((g) => g.id === id)
    if (i === -1) {
        drawnShapes.value.push({ id, type, paths: cloned })
    } else {
        drawnShapes.value[i].paths = cloned
        drawnShapes.value[i].type = type
    }
}
function updateShapePaths(id: string, paths: any[]) {
    const g = drawnShapes.value.find((g) => g.id === id)
    if (!g) return
    const src = paths === undefined ? [] : paths
    g.paths = JSON.parse(JSON.stringify(src))
}
function removeShape(id: string) {
    drawnShapes.value = drawnShapes.value.filter((g) => g.id !== id)
}

// 兼容：矩形 geometry 不同版本字段差异；优先 paths -> bounds -> center+width+height
function extractRectangleCornersFromGeo(geo: any) {
    if (!geo) return []
    if (geo.paths && geo.paths.length && geo.paths[0]?.length) {
        return JSON.parse(JSON.stringify(geo.paths[0]))
    }
    const b = geo.bounds
    if (b) {
        try {
            const ne = b.getNorthEast?.() || b.ne || b.NE
            const sw = b.getSouthWest?.() || b.sw || b.SW
            if (ne && sw) {
                const se = { lat: sw.lat, lng: ne.lng }
                const nw = { lat: ne.lat, lng: sw.lng }
                return [
                    { lat: sw.lat, lng: sw.lng },
                    se,
                    { lat: ne.lat, lng: ne.lng },
                    nw,
                ]
            }
        } catch {}
    }
    if (
        geo.center &&
        typeof geo.width === 'number' &&
        typeof geo.height === 'number'
    ) {
        const { lat, lng } = geo.center
        const halfW = geo.width / 2
        const halfH = geo.height / 2
        const metersPerLatDeg = 111320
        const metersPerLngDeg = 111320 * Math.cos((lat * Math.PI) / 180)
        if (!metersPerLngDeg) return []
        const dLat = halfH / metersPerLatDeg
        const dLng = halfW / metersPerLngDeg
        const sw = { lat: lat - dLat, lng: lng - dLng }
        const se = { lat: lat - dLat, lng: lng + dLng }
        const ne = { lat: lat + dLat, lng: lng + dLng }
        const nw = { lat: lat + dLat, lng: lng - dLng }
        return [sw, se, ne, nw]
    }
    return []
}

// 新增: 全量重建 drawnShapes（比逐条更新更稳，确保编辑后的最新坐标）
function rebuildShapesFromOverlays() {
    if (!overlaysRef.value) return
    const result: DrawnShape[] = []
    ;(['polygon', 'circle', 'rectangle'] as OverlayId[]).forEach((type) => {
        const ov: any = (overlaysRef.value as any)[type]
        if (!ov?.getGeometries) return
        let geos: any[] = []
        try {
            geos = ov.getGeometries() || []
        } catch {}
        geos.forEach((g: any) => {
            if (type === 'polygon') {
                // 识别被当作 polygon 回显的矩形
                const isRect = g?.properties?.realType === 'RECTANGLE'
                const finalType: OverlayId = isRect ? 'rectangle' : 'polygon'
                let paths = g.paths
                try {
                    if (
                        (!paths || !paths.length) &&
                        typeof g.getPaths === 'function'
                    ) {
                        const p = g.getPaths()
                        if (p && p.length) paths = p
                    }
                } catch {}
                result.push({
                    id: g.id,
                    type: finalType,
                    paths: JSON.parse(JSON.stringify(paths || [])),
                })
            } else if (type === 'circle') {
                result.push({
                    id: g.id,
                    type,
                    paths: [
                        {
                            center: { lat: g.center?.lat, lng: g.center?.lng },
                            radius: g.radius,
                        },
                    ],
                })
            } else if (type === 'rectangle') {
                // 用户新画的真 rectangle（仍然支持编辑保存）
                let rectPath: any[] = extractRectangleCornersFromGeo(g)
                result.push({
                    id: g.id,
                    type: 'rectangle',
                    paths: [JSON.parse(JSON.stringify(rectPath))],
                })
            }
        })
    })
    drawnShapes.value = result
}

// 新增: 从 overlay 实时获取最新几何并同步
function updateShapeFromOverlay(geometryId: string, overlayId: OverlayId) {
    if (!overlaysRef.value) return
    const overlay = overlaysRef.value[overlayId]
    if (!overlay?.getGeometries) return
    try {
        const geos = overlay.getGeometries()
        const geo = geos.find((g: any) => g.id === geometryId)
        if (!geo) return
        const norm = normalizePaths(overlayId, geo)
        updateShapePaths(geo.id, norm)
    } catch (e) {
        console.warn('[updateShapeFromOverlay] 获取几何失败', e)
    }
}

// 新增: syncAll 统一重建与打印
function syncAll(tag: string) {
    // 强制全量同步
    rebuildShapesFromOverlays()
}

// ========== 回显相关新增开始 ==========
function echoGeoList() {
    if (!overlaysRef.value || !window.TMap) return
    const circleGeos: any[] = []
    const polygonGeos: any[] = []
    const rectangleGeos: any[] = [] // 保留变量但不使用（兼容原逻辑）
    const rectangleAsPolygonFallback: any[] = []

    geoList.forEach((item) => {
        if (!item) return
        const type = (item.geofenceType || '').toUpperCase()
        if (type === 'CIRCLE' && item.center) {
            const arr = item.center.split(',')
            if (arr.length === 2) {
                const lng = parseFloat(arr[0])
                const lat = parseFloat(arr[1])
                if (!isNaN(lat) && !isNaN(lng)) {
                    circleGeos.push({
                        id: item.id || `circle_${Date.now()}`,
                        center: new window.TMap.LatLng(lat, lng),
                        radius: item.radius || 0,
                        properties: { source: 'echo' },
                    })
                }
            }
        } else if (type === 'POLYGON' && item.points) {
            const pts = item.points
                .split(';')
                .map((s: string) => s.trim())
                .filter(Boolean)
                .map((p: string) => {
                    const [lng, lat] = p.split(',').map(parseFloat)
                    return new window.TMap.LatLng(lat, lng)
                })
            if (pts.length) {
                polygonGeos.push({
                    id: item.id || `polygon_${Date.now()}`,
                    paths: [pts],
                    properties: { source: 'echo' },
                })
            }
        } else if (
            (item.geofenceType || '').toUpperCase() === 'RECTANGLE' &&
            item.points
        ) {
            // 解析四点 -> 生成 polygon path
            const pts = item.points
                .split(';')
                .map((s) => s.trim())
                .filter(Boolean)
                .map((p) => {
                    const [lng, lat] = p.split(',').map(parseFloat)
                    return { lat, lng }
                })
            if (pts.length >= 2) {
                let minLat = 90,
                    maxLat = -90,
                    minLng = 180,
                    maxLng = -180
                pts.forEach((p) => {
                    if (p.lat < minLat) minLat = p.lat
                    if (p.lat > maxLat) maxLat = p.lat
                    if (p.lng < minLng) minLng = p.lng
                    if (p.lng > maxLng) maxLng = p.lng
                })
                const rectPolyPath = [
                    new window.TMap.LatLng(minLat, minLng),
                    new window.TMap.LatLng(minLat, maxLng),
                    new window.TMap.LatLng(maxLat, maxLng),
                    new window.TMap.LatLng(maxLat, minLng),
                ]
                // 统一直接作为 polygon 回显（真实类型放 properties.realType）
                polygonGeos.push({
                    id: item.id || `rectpoly_${Date.now()}`,
                    paths: [rectPolyPath],
                    styleId: 'poly',
                    properties: {
                        source: 'echo_rect_poly',
                        realType: 'RECTANGLE',
                        rawPoints: item.points,
                    },
                })
            }
        }
    })

    if (circleGeos.length) overlaysRef.value.circle.setGeometries(circleGeos)
    if (polygonGeos.length) overlaysRef.value.polygon.setGeometries(polygonGeos)

    // 回显矩形为多边形后，清空矩形 overlay（避免用户误以为没加载）
    overlaysRef.value.rectangle.setGeometries([])

    // 直接同步 & 自动适配
    rebuildShapesFromOverlays()
    autoFitOverlays()
}

// 新增: 使用各 overlay 自带的 getBounds 来自动适配视野，避免手写经纬度计算
function autoFitOverlays() {
    if (!mapInstance.value || !overlaysRef.value || !window.TMap) return

    const circleOv: any = overlaysRef.value.circle
    const polygonOv: any = overlaysRef.value.polygon
    const rectOv: any = overlaysRef.value.rectangle

    // 提取几何
    let circles: any[] = []
    let polygons: any[] = []
    let rectangles: any[] = []
    try {
        circles = circleOv?.getGeometries?.() || []
    } catch {}
    try {
        polygons = polygonOv?.getGeometries?.() || []
    } catch {}
    try {
        rectangles = rectOv?.getGeometries?.() || []
    } catch {}

    const hasAny = circles.length + polygons.length + rectangles.length > 0
    if (!hasAny) return

    // 工具：计算圆 bounds（包含半径）
    const buildCircleBounds = (c: any) => {
        const lat = c.center?.lat ?? c.center?.getLat?.()
        const lng = c.center?.lng ?? c.center?.getLng?.()
        const r = c.radius || 0
        if (!lat || !lng || !r) {
            const ll = c.center
            return ll ? new window.TMap.LatLngBounds(ll, ll) : null
        }
        const dLat = r / 111320
        const metersPerLngDeg = 111320 * Math.cos((lat * Math.PI) / 180)
        const dLng = r / metersPerLngDeg
        const sw = new window.TMap.LatLng(lat - dLat, lng - dLng)
        const ne = new window.TMap.LatLng(lat + dLat, lng + dLng)
        return new window.TMap.LatLngBounds(sw, ne)
    }

    // 工具：从 polygon / rectangle geometry 获取所有点
    const extractPathsBounds = (g: any) => {
        const all: any[] = []
        const paths = g.paths || []
        paths.forEach(
            (p: any[]) =>
                p &&
                p.forEach((pt) => {
                    const lat = pt.lat ?? pt.getLat?.()
                    const lng = pt.lng ?? pt.getLng?.()
                    if (lat !== undefined && lng !== undefined)
                        all.push({ lat, lng })
                })
        )
        if (!all.length) return null
        let minLat = 90,
            maxLat = -90,
            minLng = 180,
            maxLng = -180
        all.forEach((p) => {
            if (p.lat < minLat) minLat = p.lat
            if (p.lat > maxLat) maxLat = p.lat
            if (p.lng < minLng) minLng = p.lng
            if (p.lng > maxLng) maxLng = p.lng
        })
        return new window.TMap.LatLngBounds(
            new window.TMap.LatLng(minLat, minLng),
            new window.TMap.LatLng(maxLat, maxLng)
        )
    }

    const mergeBounds = (a: any, b: any) => {
        if (!a) return b
        if (!b) return a
        try {
            if (a.union) return a.union(b)
            // fallback
            const sw1 = a.getSouthWest(),
                ne1 = a.getNorthEast()
            const sw2 = b.getSouthWest(),
                ne2 = b.getNorthEast()
            const sw = new window.TMap.LatLng(
                Math.min(sw1.lat, sw2.lat),
                Math.min(sw1.lng, sw2.lng)
            )
            const ne = new window.TMap.LatLng(
                Math.max(ne1.lat, ne2.lat),
                Math.max(ne1.lng, ne2.lng)
            )
            return new window.TMap.LatLngBounds(sw, ne)
        } catch {
            return a
        }
    }

    // 生成所有 bounds
    let totalBounds: any = null
    circles.forEach((c) => {
        const b = buildCircleBounds(c)
        if (b) totalBounds = mergeBounds(totalBounds, b)
    })
    polygons.forEach((p) => {
        const b = extractPathsBounds(p)
        if (b) totalBounds = mergeBounds(totalBounds, b)
    })
    rectangles.forEach((r) => {
        const b = extractPathsBounds(r)
        if (b) totalBounds = mergeBounds(totalBounds, b)
    })

    if (!totalBounds) return

    // 单个图形专用逻辑（更平滑）
    const single =
        (circles.length === 1 &&
            polygons.length === 0 &&
            rectangles.length === 0) ||
        (circles.length === 0 &&
            polygons.length === 1 &&
            rectangles.length === 0) ||
        (circles.length === 0 &&
            polygons.length === 0 &&
            rectangles.length === 1)

    const applyFit = () => {
        if (single && circles.length === 1) {
            const c = circles[0]
            const lat = c.center?.lat ?? c.center?.getLat?.()
            const lng = c.center?.lng ?? c.center?.getLng?.()
            if (lat !== undefined && lng !== undefined) {
                mapInstance.value.setCenter(new window.TMap.LatLng(lat, lng))
                // 根据半径估算 zoom
                const r = c.radius || 0
                let zoom = 13
                if (r > 8000) zoom = 12
                if (r > 15000) zoom = 11
                if (r > 30000) zoom = 10
                if (r > 60000) zoom = 9
                if (r < 3000) zoom = 14
                mapInstance.value.setZoom?.(zoom)
                return
            }
        }
        // 多图或非 circle 单图：fitBounds
        mapInstance.value.fitBounds?.(totalBounds, { padding: 40 })
    }

    // 延迟到下一帧，确保渲染完成后再做视野适配
    requestAnimationFrame(() => {
        applyFit()
        // 再次兜底：若地图仍然停留默认中心，可再尝试一次
        setTimeout(() => {
            // 可根据需要添加检查逻辑，这里直接不重复操作以避免跳动
        }, 120)
    })
}
// ========== 回显相关新增结束 ==========

// ---------------- 生命周期 ----------------
onMounted(async () => {
    try {
        await nextTick()
        await ensureMapAndEditor()
        echoGeoList()
        ensureIdleMode() // 再次保险
        console.log('[Init] 已回显 geoList 并保持非绘制态')
    } catch (err) {
        console.error('[Init Error]', err)
    }
    // window.addEventListener('keydown', onKeyDown)
})

onUnmounted(() => {
    // window.removeEventListener('keydown', onKeyDown)
    // 编辑器
    if (geometryEditorRef.value) {
        try {
            geometryEditorRef.value.destroy()
        } catch {}
        geometryEditorRef.value = null
    }
    // 覆盖物
    if (overlaysRef.value) {
        Object.values(overlaysRef.value).forEach((ov) => {
            try {
                ov.setMap(null)
            } catch {}
        })
        overlaysRef.value = null
    }
    // 地图
    if (mapInstance.value) {
        try {
            mapInstance.value.destroy()
        } catch {}
        mapInstance.value = null
    }
    console.log('[Unmount] 清理完成')
})
// 新增: 保存前同步最新数据
function commitLatestBeforeSave() {
    // 若当前有选中正在编辑的几何，先单独更新一次
    if (selectedGeometry.value) {
        updateShapeFromOverlay(
            selectedGeometry.value.id,
            selectedGeometry.value.overlayId
        )
    }
    // 全量重建以确保所有 overlay 的最终形状被采集
    rebuildShapesFromOverlays()
}

// 修改: handleSave 提交前获取最新
const handleSave = () => {
    commitLatestBeforeSave()
    // 再次保证所有矩形都有角点
    drawnShapes.value
        .filter((s) => s.type === 'rectangle')
        .forEach((r) => {
            if (!r.paths?.[0]?.length) {
                const filled = getRectangleCoords(r.id)
                if (filled.length) {
                    console.log('[Rectangle Filled On Save]', r.id, filled)
                }
            }
        })
    const rectangles = drawnShapes.value
        .filter((s) => s.type === 'rectangle')
        .map((s) => ({ id: s.id, corners: s.paths[0] || [] }))
    console.log('矩形坐标列表 rectangles:', rectangles)
    console.log(
        '提交数据(all shapes):',
        JSON.parse(JSON.stringify(drawnShapes.value))
    )
    // TODO: 发送 { shapes: drawnShapes.value, rectangles } 到后端
}

// 新增: 获取矩形四个点 (若为空尝试从 overlay 直接刷新一次)
function getRectangleCoords(id: string) {
    const shape = drawnShapes.value.find(
        (s) => s.id === id && s.type === 'rectangle'
    )
    if (shape && shape.paths?.[0]?.length) return shape.paths[0]
    // 兜底：再从 overlay 直接抓一次
    try {
        const geos = overlaysRef.value?.rectangle?.getGeometries?.() || []
        const g = geos.find((g: any) => g.id === id)
        if (g) {
            let arr = []
            if (g.paths && g.paths.length && g.paths[0]?.length) {
                arr = JSON.parse(JSON.stringify(g.paths[0]))
            } else {
                arr = extractRectangleCornersFromGeo(g)
            }
            if (arr.length) {
                updateShapePaths(id, [arr])
                return arr
            }
        }
    } catch {}
    return []
}

const searchPOI = () => {
    if (!searchQuery.value) return

    searching.value = true
    searchResults.value = []
    // 使用腾讯地图官方地点搜索 REST API (JSONP) 代替模拟数据
    // 说明: 直接 fetch 可能会遇到 CORS 限制，故采用 JSONP 动态 script 方式
    const key = '25IBZ-CEHCT-7GQX6-VGJG6-5D43Z-P5F63' // 已在脚本标签中使用的 key
    // 这里使用“北京”作为默认区域，可按需改成其他城市，或扩展为下拉选择
    const region = '北京'
    const keyword = encodeURIComponent(searchQuery.value.trim())
    // 官方搜索接口: https://apis.map.qq.com/ws/place/v1/search
    // boundary 可用 region(城市,0) 或 nearby(lat,lng,radius)
    const boundary = encodeURIComponent(`region(${region},0)`)
    const callbackName = 'qqmap_cb_' + Date.now()
    const url = `https://apis.map.qq.com/ws/place/v1/search?keyword=${keyword}&boundary=${boundary}&page_size=20&page_index=1&key=${key}&output=jsonp&callback=${callbackName}`

    jsonpRequest(url, callbackName)
        .then((data) => {
            console.log('搜索结果:', data)
            if (!data || data.status !== 0 || !Array.isArray(data.data)) {
                console.warn('搜索无结果或返回异常')
                searchResults.value = []
                return
            }
            // 转换结果
            const list = data.data.map((item) => ({
                title: item.title || item.name || '未命名地点',
                address: item.address || '',
                lat: item.location ? item.location.lat : 0,
                lng: item.location ? item.location.lng : 0,
            }))
            searchResults.value = list
            console.log('转换后结果:', searchResults.value)

            // if (list.length > 0) {
            //     const first = list[0]
            //     const position = new TMap.LatLng(first.lat, first.lng)
            //     addMarker(position, first.title)
            // }
        })
        .catch((err) => {
            console.warn('搜索失败:', err)
            searchResults.value = []
        })
        .finally(() => {
            searching.value = false
        })
}

// 将地图中心移动到选定位置
const centerMap = (result) => {
    const position = new TMap.LatLng(result.lat, result.lng)
    addMarker(position, result.title)
}
// JSONP 请求封装
const jsonpRequest = (url, callbackName, timeout = 8000) => {
    return new Promise((resolve, reject) => {
        const script = document.createElement('script')
        let timer = null

        window[callbackName] = (data) => {
            clearTimeout(timer)
            resolve(data)
            cleanup()
        }

        const cleanup = () => {
            if (script.parentNode) script.parentNode.removeChild(script)
            try {
                delete window[callbackName]
            } catch (e) {
                window[callbackName] = undefined
            }
        }

        script.src = url
        script.onerror = () => {
            clearTimeout(timer)
            reject(new Error('JSONP 网络错误'))
            cleanup()
        }
        document.body.appendChild(script)

        timer = setTimeout(() => {
            reject(new Error('JSONP 超时'))
            cleanup()
        }, timeout)
    })
}
// 添加标记
const addMarker = (position, title) => {
    // 先清除所有现有标记
    clearMarkers()

    // 创建几何图层
    const markerLayer = new TMap.MultiMarker({
        map: map,
        styles: {
            marker: new TMap.MarkerStyle({
                width: 25,
                height: 35,
                anchor: { x: 12.5, y: 35 },
                src: 'https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/marker.png',
            }),
        },
        geometries: [
            {
                id: 'marker',
                styleId: 'marker',
                position: position,
                properties: {
                    title: title,
                },
            },
        ],
    })

    markers.push(markerLayer)

    // 将地图中心移动到标记位置
    map.setCenter(position)
}

// 清除所有标记
const clearMarkers = () => {
    markers.forEach((marker) => {
        marker.setMap(null)
    })
    markers = []
}
</script>

<style lang="scss" scoped>
/* 新增: 工具栏样式 */
.map-toolbar {
    position: absolute;
    top: 15px;
    right: 100px;
    z-index: 99999; /* 原 1000 => 显著提升，确保盖住地图交互层 */
    display: flex;
    gap: 6px;
    background: #fff;
    padding: 10px 12px;
    border-radius: 6px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
        'Helvetica Neue', Arial;
    pointer-events: auto;
}
.map-toolbar .tool-btn {
    padding: 6px 14px;
    border: 1px solid #d9d9d9;
    border-radius: 4px;
    cursor: pointer;
    font-size: 13px;
    user-select: none;
    background: #f7f7f7;
    transition: 0.15s;
}
.map-toolbar .tool-btn:hover {
    background: #eee;
}
.map-toolbar .tool-btn.active {
    background: #1890ff;
    color: #fff;
    border-color: #1890ff;
}
.map-toolbar .tool-btn.danger {
    background: #fff1f0;
    border-color: #ffa39e;
    color: #cf1322;
}
.map-toolbar .tool-btn.danger:hover {
    background: #ffe2de;
}

.container {
    width: 100%;
    height: 100vh;
    padding: 0;
    margin: 0;
    position: relative;
}

.map-container {
    width: 100%;
    height: 100%;
}
</style>
<style>
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
}

body {
    background-color: #f5f7fa;
    color: #333;
    padding: 20px;
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 20px;
}

header {
    text-align: center;
    padding: 15px 0;
}

h1 {
    color: #2c3e50;
    font-size: 2.2rem;
    margin-bottom: 10px;
}

.description {
    color: #7f8c8d;
    font-size: 1.1rem;
    max-width: 800px;
    margin: 0 auto;
}

.app-container {
    display: flex;
    gap: 20px;
    min-height: 600px;
}

.map-container {
    flex: 1;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
    background: white;
}

#map {
    width: 100%;
    height: 100%;
    min-height: 500px;
}

.search-panel {
    width: 350px;
    background: white;
    border-radius: 12px;
    padding: 20px;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
    display: flex;
    flex-direction: column;
}

.search-title {
    font-size: 1.4rem;
    color: #2c3e50;
    margin-bottom: 20px;
    padding-bottom: 10px;
    border-bottom: 2px solid #eee;
    display: flex;
    align-items: center;
    gap: 10px;
}

.search-box {
    display: flex;
    margin-bottom: 20px;
    gap: 10px;
}

.search-input {
    flex: 1;
    padding: 12px 16px;
    border: 1px solid #ddd;
    border-radius: 8px;
    font-size: 1rem;
    transition: all 0.3s;
}

.search-input:focus {
    outline: none;
    border-color: #3498db;
    box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
}

.search-btn {
    padding: 12px 20px;
    background: #3498db;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-weight: 500;
    transition: all 0.3s;
}

.search-btn:hover {
    background: #2980b9;
}

.search-btn:disabled {
    background: #bdc3c7;
    cursor: not-allowed;
}

.results-container {
    flex: 1;
    overflow-y: auto;
}

.result-item {
    padding: 15px;
    border-bottom: 1px solid #eee;
    cursor: pointer;
    transition: all 0.2s;
    border-radius: 6px;
}

.result-item:hover {
    background: #f1f8ff;
}

.result-item h3 {
    font-size: 1.1rem;
    color: #2c3e50;
    margin-bottom: 8px;
}

.result-item p {
    color: #7f8c8d;
    font-size: 0.9rem;
    margin-bottom: 5px;
}

.no-results {
    text-align: center;
    padding: 30px 0;
    color: #95a5a6;
}

.loading {
    text-align: center;
    padding: 20px 0;
    color: #3498db;
}

.footer {
    text-align: center;
    padding: 20px 0;
    color: #7f8c8d;
    font-size: 0.9rem;
}

@media (max-width: 900px) {
    .app-container {
        flex-direction: column;
    }

    .map-container {
        height: 400px;
    }

    .search-panel {
        width: 100%;
    }
}
</style>
